﻿/* Copyright (c) 2010, John Cronin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the copyright holder nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

using System;
using System.Collections.Generic;
using System.Text;

namespace tysila
{
    partial class Assembler
    {
        private MemberRequestor _requestor; public MemberRequestor Requestor { get { return _requestor; } }
        public class MemberRequestor
        {
            private Assembler ass; public Assembler Assembler { get { return ass; } }
            public MemberRequestor(Assembler assembler) { ass = assembler; }
            public List<Metadata> ModulesToAssemble = new List<Metadata>();
            internal object meth_lock = new object();
            internal object type_lock = new object();
            internal object ti_lock = new object();
            internal object fi_lock = new object();
            internal object mi_lock = new object();

            public void RequestMethod(Assembler.MethodToCompile mtc)
            {
                if ((ModulesToAssemble.Count == 0) || (ModulesToAssemble.Contains(mtc.meth.m)))
                {
                    lock (meth_lock)
                    {
                        if ((!ExistsIn(mtc, _requested_meths)) && (!ExistsIn(mtc, _compiled_meths)))
                            _requested_meths.Add(mtc);
                    }
                }
            }

            public void RequestTypeInfo(Assembler.TypeToCompile ttc)
            {
                if ((ModulesToAssemble.Count == 0) || (ModulesToAssemble.Contains(ttc.type.m)))
                {
                    lock (ti_lock)
                    {
                        if ((!ExistsIn(ttc, _requested_tis)) && (!ExistsIn(ttc, _compiled_tis)))
                            _requested_tis.Add(ttc);
                    }
                }
            }

            public void RequestType(Assembler.TypeToCompile ttc)
            {
                if ((ModulesToAssemble.Count == 0) || (ModulesToAssemble.Contains(ttc.type.m)))
                {
                    lock (type_lock)
                    {
                        if ((!ExistsIn(ttc, _requested_types)) && (!ExistsIn(ttc, _compiled_types)))
                            _requested_types.Add(ttc);
                    }
                }
            }

            public void RequestMethodInfo(Assembler.MethodToCompile mtc)
            {
                if ((ModulesToAssemble.Count == 0) || (ModulesToAssemble.Contains(mtc.meth.m)))
                {
                    lock (mi_lock)
                    {
                        if ((!ExistsIn(mtc, _requested_mis)) && (!ExistsIn(mtc, _compiled_mis)))
                            _requested_mis.Add(mtc);
                    }
                }
            }

            public void RequestFieldInfo(Assembler.FieldToCompile ftc)
            {
                if ((ModulesToAssemble.Count == 0) || (ModulesToAssemble.Contains(ftc.field.m)))
                {
                    lock (fi_lock)
                    {
                        if ((!ExistsIn(ftc, _requested_fis)) && (!ExistsIn(ftc, _compiled_fis)))
                            _requested_fis.Add(ftc);
                    }
                }
            }

            private bool ExistsIn(Assembler.MethodToCompile mtc, List<Assembler.MethodToCompile> mtcs)
            {
                foreach (Assembler.MethodToCompile cur_mtc in mtcs)
                {
                    if (Signature.MethodCompare(mtc, cur_mtc, ass, true) == true)
                        return true;
                }
                return false;
            }

            private bool ExistsIn(Assembler.TypeToCompile ttc, List<Assembler.TypeToCompile> ttcs)
            {
                foreach (Assembler.TypeToCompile cur_ttc in ttcs)
                {
                    if (Signature.TypeCompare(ttc, cur_ttc, ass) == true)
                        return true;
                }
                return false;
            }

            private bool ExistsIn(Assembler.FieldToCompile ftc, List<Assembler.FieldToCompile> ftcs)
            {
                foreach (Assembler.FieldToCompile cur_ftc in ftcs)
                {
                    if (Signature.FieldCompare(ftc, cur_ftc, ass) == true)
                        return true;
                }
                return false;
            }

            private List<Assembler.TypeToCompile> _requested_tis = new List<TypeToCompile>();
            private List<Assembler.TypeToCompile> _requested_types = new List<TypeToCompile>();
            private List<Assembler.MethodToCompile> _requested_meths = new List<MethodToCompile>();
            private List<Assembler.FieldToCompile> _requested_fis = new List<FieldToCompile>();
            private List<Assembler.MethodToCompile> _requested_mis = new List<MethodToCompile>();

            private List<Assembler.TypeToCompile> _compiled_tis = new List<TypeToCompile>();
            private List<Assembler.TypeToCompile> _compiled_types = new List<TypeToCompile>();
            private List<Assembler.MethodToCompile> _compiled_meths = new List<MethodToCompile>();
            private List<Assembler.FieldToCompile> _compiled_fis = new List<FieldToCompile>();
            private List<Assembler.MethodToCompile> _compiled_mis = new List<MethodToCompile>();

            public bool MoreTypeInfos { get { if (_requested_tis.Count == 0) return false; return true; } }
            public bool MoreTypes { get { if (_requested_types.Count == 0) return false; return true; } }
            public bool MoreMethods { get { if (_requested_meths.Count == 0) return false; return true; } }
            public bool MoreFieldInfos { get { if (_requested_fis.Count == 0) return false; return true; } }
            public bool MoreMethodInfos { get { if (_requested_mis.Count == 0) return false; return true; } }
            public bool MoreToDo { get { lock (ti_lock) { lock (meth_lock) { lock (type_lock) { lock (fi_lock) { lock (mi_lock) { if (MoreTypeInfos || MoreTypes || MoreMethods || MoreFieldInfos || MoreMethodInfos) return true; else return false; } } } } } } }

            public void PurgeRequestedTypes() { _requested_types.Clear(); }
            public void PurgeRequestedTypeInfos() { _requested_tis.Clear(); }
            public void PurgeRequestedMethods() { _requested_meths.Clear(); }
            public void PurgeRequestedFieldInfos() { _requested_fis.Clear(); }
            public void PurgeRequestedMethodInfos() { _requested_mis.Clear(); }
            public void PurgeAssembledTypes() { _compiled_types.Clear(); }
            public void PurgeAssembledTypeInfos() { _compiled_tis.Clear(); }
            public void PurgeAssembledMethods() { _compiled_meths.Clear(); }
            public void PurgeAssembledFieldInfos() { _compiled_fis.Clear(); }
            public void PurgeAssembledMethodInfos() { _compiled_mis.Clear(); }
            public void PurgeAll() { PurgeAssembledMethods(); PurgeAssembledTypeInfos(); PurgeAssembledTypes(); PurgeRequestedMethods(); PurgeRequestedTypeInfos(); PurgeRequestedTypes();
            PurgeAssembledFieldInfos(); PurgeAssembledMethodInfos(); PurgeRequestedFieldInfos(); PurgeRequestedMethodInfos();
            }

            public Assembler.MethodToCompile GetNextMethod()
            {
                if (!MoreMethods)
                    throw new Exception("No more methods");
                Assembler.MethodToCompile ret = _requested_meths[0];
                _compiled_meths.Add(ret);
                _requested_meths.RemoveAt(0);
                return ret;
            }
            public Assembler.TypeToCompile GetNextType()
            {
                if (!MoreTypes)
                    throw new Exception("No more types");
                Assembler.TypeToCompile ret = _requested_types[0];
                _compiled_types.Add(ret);
                _requested_types.RemoveAt(0);
                return ret;
            }
            public Assembler.TypeToCompile GetNextTypeInfo()
            {
                if (!MoreTypeInfos)
                    throw new Exception("No more typeinfos");
                Assembler.TypeToCompile ret = _requested_tis[0];
                _compiled_tis.Add(ret);
                _requested_tis.RemoveAt(0);
                return ret;
            }
            public Assembler.MethodToCompile GetNextMethodInfo()
            {
                if (!MoreMethodInfos)
                    throw new Exception("No more methodinfos");
                Assembler.MethodToCompile ret = _requested_mis[0];
                _compiled_mis.Add(ret);
                _requested_mis.RemoveAt(0);
                return ret;
            }
            public Assembler.FieldToCompile GetNextFieldInfo()
            {
                if (!MoreFieldInfos)
                    throw new Exception("No more fieldinfos");
                Assembler.FieldToCompile ret = _requested_fis[0];
                _compiled_fis.Add(ret);
                _requested_fis.RemoveAt(0);
                return ret;
            }
        }
    }
}
